package com.tidy.seed.configuration;

import com.tidy.seed.annotation.NoToken;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Configuration
@EnableOpenApi
public class SwaggerConfig {

    // 从配置文件读取是否启用Swagger，默认为false
    @Value("${swagger.enabled:true}")
    private boolean swaggerEnabled;

    @Bean
    public Docket getDocket() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .enable(swaggerEnabled) // 根据配置决定是否启用
                // 添加 Token 认证配置
                .securitySchemes(Collections.singletonList(apiKey()))
                .securityContexts(Collections.singletonList(securityContext()))
                .select()
                .apis(multipleBasePackages(
                        "com.tidy.seed.controller",
                        "com.tidy.seed.admin.system.controller",
                        "com.tidy.seed.admin.arcsoft.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Seed Boot API 文档")
                .description("Seed Boot项目接口文档，包含用户管理、系统配置等模块接口")
                .contact(new Contact("开发团队", "https://www.seed-project.com", "dev@seed-project.com"))
                .version("v1.0.0")
                .build();
    }

    /**
     * 支持多个 basePackage 的组合（递归子包），等价于 or 合并
     */
    private Predicate<RequestHandler> multipleBasePackages(String... basePackages) {
        List<Predicate<RequestHandler>> predicates = Arrays.stream(basePackages)
                .map(RequestHandlerSelectors::basePackage)
                .collect(Collectors.toList());
        return predicates.stream().reduce(x -> false, Predicate::or);
    }

    /**
     * 配置 API Key（从 header 里取 Authorization）
     */
    private ApiKey apiKey() {
        return new ApiKey("Authorization", "Authorization", "header");
    }

    /**
     * 配置安全上下文：排除带有 @NoToken 的控制器或方法
     */
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .operationSelector(this::needsSecurity) // 过滤哪些操作需要安全
                .build();
    }

    /**
     * 只有没有标注 @NoToken 的才启用认证
     */
    private boolean needsSecurity(OperationContext operationContext) {
        boolean hasMethodNoToken = operationContext.findAnnotation(NoToken.class).isPresent();
        boolean hasControllerNoToken = operationContext.findControllerAnnotation(NoToken.class).isPresent();
        return !(hasMethodNoToken || hasControllerNoToken);
    }

    /**
     * 默认的安全引用（全局作用域）
     */
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope =
                new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[]{authorizationScope};
        return Collections.singletonList(new SecurityReference("Authorization", authorizationScopes));
    }
}
